'''
Let's implement a minimal implementation for the judge module.
We import soj-core here and do:
1. Init: load all problem configs from db, cache them.
2. Receive submission from webmgmt, create a record in db with status "Pending", put the submission into the judging queue.
3. Judging loop: get submission from judging queue, run the judging according to the problem
in current version, we only implement a single-threaded judging loop so 
it can only judge one submission at a time.
4. After judging, update the record in db with the result. Then send it to submitter module.
'''
from soj.judgetask.oi.judge import OIProblem
from soj.judgetask.text.judge import TextProblem
from soj.common.lang import Language
from soj.common.util import ensure_file
from sjudger.config import AVAILABLE_PROBLEM_TYPES,SCORING_FILE,META_FILE,ProblemType
from judge.models import Problem,Record
import logging as log
from typing import Dict,TypedDict
from pathlib import Path
import json
# although we have no abstraction now, but it not a big deal. take it easy it just a demo project :)
from judge.problemcfg import OIConfig,TextConfig
class Judger:
    # problem cache is public and static
    problem_cache:Dict[str,OIProblem|TextProblem]={}
    # run once at startup
    def load_problem_cache(self):
        log.info("[Judger] Full problem update")
        prob=Problem.objects.all()
        succ=0
        for i in prob:
            log.info(f"[Judger] Detected {i.problem_id}")
            bsd=Path(i.config_path).resolve()
            try:
                meta_p=bsd/META_FILE
                scoring_p=bsd/SCORING_FILE
                ensure_file(meta_p),ensure_file(scoring_p)
                with open(meta_p,"r+") as f:
                    mt=json.loads(str(f.read()))
                with open(scoring_p,"r+") as f:
                    sc=json.loads(str(f.read()))
            except Exception as e:
                log.error(f"[Judger] Error {e} occured when loading {i.problem_id}")
                continue
            if i.problem_type==ProblemType.OI:
                self.problem_cache[i.problem_id]=OIProblem(bsd,mt,sc)
            if i.problem_type==ProblemType.TEXT:
                self.problem_cache[i.problem_id]=TextProblem(bsd,mt,sc)
            succ+=1
        log.info(f"[Judger] Completed, loaded {succ} problems")
    def _oi_judge(self,opt:OIConfig):
        if opt["problem_id"] not in self.problem_cache:
            log.error(f"[Judger] Problem {opt['problem_id']} not found")
            raise KeyError("No such problem")
        pb=self.problem_cache[opt["problem_id"]]
        pb.init_partcipant(opt["code"],Language[opt["lang"]],opt["settings"])
        return pb.judge()
        # note that we have not called pb.release_partcipant 